﻿using System;
using System.Collections.Generic;
using System.Text;
using Avanade.Datamining.SMO;
using Microsoft.SqlServer.DataMining.PluginAlgorithms;

namespace Avanade.Datamining
{
    public class InstancesWrapper : Instances, ICaseProcessor
    {
        private PushCaseSet caseSet;
        Algorithm algorithm;
        private uint target1;
        private uint target2;
        private long[] mapping;

        public InstancesWrapper(PushCaseSet _caseSet, uint _target1, uint _target2, uint[] _examples, uint _totalCases, uint _targetAttribute)
        {
            caseSet = _caseSet;
            target1 = _target1;
            target2 = _target2;

            MappingMaker maker = new MappingMaker(_totalCases, _target1, _target2, _targetAttribute);
            caseSet.StartCases(maker);
            mapping = maker.mapping;
            //maybe randomize
        }


        public int NumberOfInstances()
        {
            return mapping.Length;
        }

        public Instance getInstance(int i)
        {
            InstanceMaker maker = new InstanceMaker(algorithm, algorithm.getTargetAttribute(), target1, target2, i);
            caseSet.StartCases(maker);
            int [] positions = new int[]{};
            double [] values = new double[]{};
            maker.positions.CopyTo(positions, 0);
            maker.result.CopyTo(values, 0);
            InstanceWrapper wrapper = new InstanceWrapper(maker.label, positions, values, algorithm.numberOfDimensions);
            return wrapper;
        }

        public double sumOfWeights()
        {
            //TODO
            return 0;
        }

        public void ProcessCase(long caseID, MiningCase inputCase)
        {
            //only read it if the individual is selected
            /*uint label;
            int attributeSize;
            double[] values;
            algo.getValues(inputCase, out values, out label, out attributeSize);
            Instance instance = new Instance(1, (int)label, values, algo.getLabels());
            instances[instance.label].addInstance(instance);
            instances[instance.label].attributeSize = attributeSize;
            total++;*/
        }


    }

    class InstanceWrapper : Instance
    {
        double[] values;
        int[] positions;
        int label;
        int size;
        public InstanceWrapper(int _label, int[] positions, double[] _values, int size)
        {
            values = _values;
            label = _label;
        }

        public int[] getPositions() { return positions; }
        public double[] getValues() { return values; }
        public int getLabel() { return label; }
        public int getSize() { return size; }
        public double getWeight() { return 1; }
        //public int[] getLabels() {return new int[]{};}

    }

    class MappingMaker : ICaseProcessor
    {
        public long[] mapping;
        private uint target1;
        private uint target2;
        private uint targetAttribute;
        private uint position;

        public MappingMaker(uint _totalCases, uint _target1, uint _target2, uint _targetAttribute)
        {
            mapping = new long[_totalCases];
            target1 = _target1;
            target2 = _target2;
            targetAttribute = _targetAttribute;
        }

        public void ProcessCase(long caseID, MiningCase inputCase)
        {
            inputCase.MoveFirst();
            bool _continue = true;
            while(_continue)
            {
                if (inputCase.Attribute == targetAttribute)
                {
                    if (inputCase.IndexValue == target1 || inputCase.IndexValue == target2)
                    {
                        mapping[position] = caseID;
                        position++;
                    }
                    _continue = false;
                }
                _continue = _continue && inputCase.MoveNext();
            }
        }
    }

    class InstanceMaker : ICaseProcessor
    {
        Algorithm algorithm;
        uint TargetAttribute;
        uint target1;
        uint target2;
        public LinkedList<double> result = new LinkedList<double>();
        public LinkedList<int> positions = new LinkedList<int>();
        //int[] positions = new int[] { };
        
        int position = 0;
        public int label = 0;
        long instanceId;
        public InstanceMaker(Algorithm _algorithm, uint _TargetAttribute, uint _target1, uint _target2, long _instanceId)
        {
            algorithm = _algorithm;
            TargetAttribute = _TargetAttribute;
            target1 = _target1;
            target2 = _target2;
            instanceId = _instanceId;

        }

        public void ProcessCase(long caseID, MiningCase inputCase)
        {
            if (caseID != instanceId)
            {
                return;
            }
            inputCase.MoveFirst();
            bool _continue = true;
            while (_continue)
            {
                
                if (inputCase.Attribute == TargetAttribute)
                {
                    if (inputCase.IndexValue == target1)
                    {
                        label = 1;
                    }
                    else
                    {
                        label = -1;
                    }
                }
                else if (inputCase.Value.IsDouble)
                {
                    double value = inputCase.DoubleValue;
                    double max = algorithm.MarginalStats.GetAttributeStats(inputCase.Attribute).Max;
                    double min = algorithm.MarginalStats.GetAttributeStats(inputCase.Attribute).Min;
                    value = (value - min) / (max - min);
                    if (Double.IsNaN(value) || Double.IsInfinity(value))
                    {
                        value = 0;
                    }

                    if(value != 0.0)
                    {
                        result.AddLast(value);
                        positions.AddLast(position);
                    }
                    //result[position] = inputCase.DoubleValue;
                    position++;
                }
                else
                {
                    for(int i=0;i<algorithm.AttributeSet.GetAttributeStateCount(inputCase.Attribute);i++){
                        if (i == inputCase.IndexValue)
                        {
                            result.AddLast(1);
                            positions.AddLast(position);
                            //result[position] = 1;
                        }
                        /*else
                        {
                            result[position] = 0;
                        }*/
                        position++;
                    }
                }
                _continue = _continue && inputCase.MoveNext();
            }
        }
    }
}
